﻿using Longbow.Cache;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.Http;

namespace Longbow.Web
{
    /// <summary>
    /// 默认 IP 地理位置定位器
    /// </summary>
    public class DefaultIPLocatorProvider : IIPLocatorProvider
    {
        private readonly ConcurrentDictionary<string, AutoExpireCacheEntry<string>> _ipPool = new ConcurrentDictionary<string, AutoExpireCacheEntry<string>>();
        private readonly IPLocatorOption _option = new IPLocatorOption();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="logger"></param>
        public DefaultIPLocatorProvider(IHttpClientFactory factory, ILogger<DefaultIPLocatorProvider> logger)
        {
            _option.HttpClient = factory.CreateClient(OnlineUsersServicesCollectionExtensions.IPSvrHttpClientName);
            _option.Logger = logger;
        }

        /// <summary>
        /// 定位方法
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public string Locate(string ip)
        {
            _option.Locator = NoneIPLocator.Instance;
            _option.Url = string.Empty;
            _option.IP = ip;
            IPLocatorServicesCollectionExtensions.ConfigureOption(_option);

            // 解析本机地址
            if (string.IsNullOrEmpty(ip) || _option.Localhosts.Any(p => p == ip)) return "本地连接";

            // IP定向器地址未设置
            if (string.IsNullOrEmpty(_option.Url)) return string.Empty;

            return _ipPool.GetOrAdd(ip, key => new AutoExpireCacheEntry<string>(_option.Locator?.Locate(_option) ?? string.Empty, _option.Period, __ => _ipPool.TryRemove(key, out _))).Value;
        }

        /// <summary>
        /// 根据指定定位器名称创建定位器方法
        /// </summary>
        /// <param name="name">IP定位器名称</param>
        /// <returns></returns>
        public static IIPLocator CreateLocator(string name)
        {
            if (name.Equals("BaiDuIPSvr", StringComparison.OrdinalIgnoreCase)) return new BaiDuIPLocator();
            else if (name.Equals("JuheIPSvr", StringComparison.OrdinalIgnoreCase)) return new JuheIPLocator();
            else return NoneIPLocator.Instance;
        }
    }
}
